home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume7 / top2 / part02 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  38.5 KB

  1. Subject:  v07i031:  Top users display for 4.2BSD, Version 2.0, Part02/02
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: William LeFebvre <phil@rice.edu>
  6. Mod.sources: Volume 7, Issue 31
  7. Archive-name: top2/Part02
  8.  
  9.  
  10. #!/bin/sh
  11. # This is a shell archive.  Remove anything before this line,
  12. # then unpack it by saving it in a file and typing "sh file".
  13. # If all goes well, you will see the message "No problems found."
  14.  
  15. # Exit status; set to 1 on "wc" errors or if would overwrite.
  16. STATUS=0
  17. # Contents:  top.c top.local.h top.man MANIFEST
  18.  
  19. echo x - top.c
  20. if test -f top.c ; then
  21.     echo top.c exists, putting output in $$top.c
  22.     OUT=$$top.c
  23.     STATUS=1
  24. else
  25.     OUT=top.c
  26. fi
  27. sed 's/^X//' > $OUT <<'@//E*O*F top.c//'
  28. Xchar *copyright =
  29. X    "Top, version 2.0, copyright (c) 1984, 1986, William LeFebvre";
  30.  
  31. X/*
  32. X *  Top users display for Berkeley Unix
  33. X *  Version 2.0
  34. X *
  35. X *  This program may be freely redistributed to other Unix sites, but this
  36. X *  entire comment MUST remain intact.
  37. X *
  38. X *  Copyright (c) 1984, 1986, William LeFebvre, Rice University
  39. X *
  40. X *  This program is designed to run on either Berkeley 4.1 or 4.2 Unix.
  41. X *  Compile with the preprocessor constant "FOUR_ONE" set to get an
  42. X *  executable that will run on Berkeley 4.1 Unix.
  43. X *
  44. X *  The Sun kernel uses scaled integers instead of floating point.
  45. X *  Compilation with the preprocessor variable "sun" gets an executable
  46. X *  that will run on Sun Unix version 1.1 or later ("sun" is automatically
  47. X *  set by the Sun C compiler).
  48. X *
  49. X *  The Pyramid splits the stack size (p_ssize) into control stack and user
  50. X *  stack sizes.  Compilation with the preprocessor variable "pyr" gets an
  51. X *  executable that will run on Pyramids ("pyr" is automatically set by the
  52. X *  Pyramid C compiler).
  53. X *
  54. X *  See the file "Changes" for more information on version-to-version changes.
  55. X */
  56.  
  57. X#include <stdio.h>
  58. X#include <pwd.h>
  59. X#include <nlist.h>
  60. X#include <signal.h>
  61. X#include <setjmp.h>
  62. X#include <sys/param.h>
  63. X#include <sys/dir.h>
  64. X#include <sys/user.h>
  65. X#include <sys/proc.h>
  66. X#include <sys/dk.h>
  67. X#include <sys/vm.h>
  68.  
  69. X/* includes specific to top */
  70. X#include "layout.h"
  71. X#include "screen.h"        /* interface to screen package */
  72. X#include "top.h"
  73. X#include "top.local.h"
  74. X#include "boolean.h"
  75.  
  76. X/* Special atoi routine returns either a non-negative number or one of: */
  77. X#define Infinity    -1
  78. X#define Invalid        -2
  79.  
  80. X/* Size of the stdio buffer given to stdout */
  81. X#define Buffersize    2048
  82.  
  83. X/* The buffer the stdio will use */
  84. Xchar stdoutbuf[Buffersize];
  85.  
  86. X/* wish list for kernel symbols */
  87.  
  88. Xstruct nlist nlst[] = {
  89. X    { "_avenrun" },
  90. X#define X_AVENRUN    0
  91. X    { "_ccpu" },
  92. X#define X_CCPU        1
  93. X    { "_cp_time" },
  94. X#define X_CP_TIME    2
  95. X    { "_hz" },
  96. X#define X_HZ        3
  97. X    { "_mpid" },
  98. X#define X_MPID        4
  99. X    { "_nproc" },
  100. X#define X_NPROC        5
  101. X    { "_proc" },
  102. X#define X_PROC        6
  103. X    { "_total" },
  104. X#define X_TOTAL        7
  105. X    { 0 },
  106. X};
  107.  
  108. X/* build Signal masks */
  109. X#define Smask(s)    (1 << ((s) - 1))
  110.  
  111. X/* for system errors */
  112. Xextern int errno;
  113.  
  114. X/* for getopt: */
  115. Xextern int  optind;
  116. Xextern char *optarg;
  117.  
  118. X/* signal handling routines */
  119. Xint leave();
  120. Xint onalrm();
  121. Xint tstop();
  122.  
  123. Xint nproc;
  124. Xint mpid;
  125.  
  126. X/* kernel "hz" variable -- clock rate */
  127. Xlong hz;
  128.  
  129. X/* All this is to calculate the cpu state percentages */
  130.  
  131. Xlong cp_time[CPUSTATES];
  132. Xlong cp_old[CPUSTATES];
  133. Xlong cp_change[CPUSTATES];
  134. Xlong total_change;
  135. Xlong mpid_offset;
  136. Xlong avenrun_offset;
  137. Xlong cp_time_offset;
  138. Xlong total_offset;
  139.  
  140. X#ifdef sun
  141. Xlong ccpu;
  142. Xlong avenrun[3];
  143. X#else
  144. Xdouble ccpu;
  145. Xdouble avenrun[3];
  146. X#endif
  147. Xdouble logcpu;
  148.  
  149. Xstruct vmtotal total;
  150.  
  151. Xstruct proc *proc;
  152. Xstruct proc *pbase;
  153. Xint bytes;
  154. Xint initialized = No;
  155. Xchar *myname = "top";
  156. Xjmp_buf jmp_int;
  157. Xchar input_waiting = No;
  158.  
  159. X/* routines that don't return int */
  160.  
  161. Xstruct passwd *getpwent();
  162. Xchar *username();
  163. Xchar *itoa();
  164. Xchar *ctime();
  165. Xchar *rindex();
  166. Xchar *kill_procs();
  167. Xchar *renice_procs();
  168.  
  169. Xint proc_compar();
  170. Xlong time();
  171.  
  172. X/* different routines for displaying the user's identification */
  173. X/* (values assigned to get_userid) */
  174. Xchar *username();
  175. Xchar *itoa7();
  176.  
  177. X/* display routines that need to be predeclared */
  178. Xint i_loadave();
  179. Xint u_loadave();
  180. Xint i_procstates();
  181. Xint u_procstates();
  182. Xint i_cpustates();
  183. Xint u_cpustates();
  184. Xint i_memory();
  185. Xint u_memory();
  186. Xint i_header();
  187. Xint u_header();
  188. Xint i_process();
  189. Xint u_process();
  190.  
  191. X/* pointers to display routines */
  192. Xint (*d_loadave)() = i_loadave;
  193. Xint (*d_procstates)() = i_procstates;
  194. Xint (*d_cpustates)() = i_cpustates;
  195. Xint (*d_memory)() = i_memory;
  196. Xint (*d_header)() = i_header;
  197. Xint (*d_process)() = i_process;
  198.  
  199. X/* buffer of proc information lines for display updating */
  200. X/* unfortunate that this must be declared globally */
  201. Xchar (* screenbuf)[Display_width];
  202.  
  203. Xmain(argc, argv)
  204.  
  205. Xint  argc;
  206. Xchar *argv[];
  207.  
  208. X{
  209. X    register struct proc *pp;
  210. X    register struct proc **prefp;
  211. X    register int i;
  212. X    register int active_procs;
  213. X    register int change;
  214.  
  215. X    static struct proc **pref;
  216. X    static char tempbuf1[50];
  217. X    static char tempbuf2[50];
  218. X    int total_procs;
  219. X    int old_sigmask;
  220. X    int proc_brkdn[7];
  221. X    int topn = Default_TOPN;
  222. X    int delay = Default_DELAY;
  223. X    int displays = 0;        /* indicates unspecified */
  224. X    long curr_time;
  225. X    char *(*get_userid)() = username;
  226. X    char *uname_field = "USERNAME";
  227. X#ifndef FOUR_ONE
  228. X    char ch;
  229. X    char msg_showing = 0;
  230. X    int readfds;
  231. X    struct timeval timeout;
  232. X#endif    
  233. X    char dostates = No;
  234. X    char do_unames = Yes;
  235. X    char do_init = No;
  236. X    char interactive = Maybe;
  237. X    char show_sysprocs = No;
  238. X    char topn_specified = No;
  239. X    char warnings = 0;
  240.  
  241. X    /* set the buffer for stdout */
  242. X    setbuffer(stdout, stdoutbuf, Buffersize);
  243.  
  244. X    /* get our name */
  245. X    if (argc > 0)
  246. X    {
  247. X    if ((myname = rindex(argv[0], '/')) == 0)
  248. X    {
  249. X        myname = argv[0];
  250. X    }
  251. X    else
  252. X    {
  253. X        myname++;
  254. X    }
  255. X    }
  256.  
  257. X    /* process options */
  258. X    while ((i = getopt(argc, argv, "Sbinus:d:")) != EOF)
  259. X    {
  260. X    switch(i)
  261. X    {
  262. X        case 'u':            /* display uid instead of name */
  263. X        do_unames = No;
  264. X        uname_field = "   UID  ";
  265. X        get_userid = itoa7;
  266. X        break;
  267.  
  268. X        case 'S':            /* show system processes */
  269. X        show_sysprocs = Yes;
  270. X        break;
  271.  
  272. X        case 'i':            /* go interactive regardless */
  273. X        interactive = Yes;
  274. X        break;
  275.  
  276. X        case 'n':            /* batch, or non-interactive */
  277. X        case 'b':
  278. X        interactive = No;
  279. X        break;
  280.  
  281. X        case 'd':            /* number of displays to show */
  282. X        if ((i = atoiwi(optarg)) == Invalid || i == 0)
  283. X        {
  284. X            fprintf(stderr,
  285. X            "%s: warning: display count should be positive -- option ignored\n",
  286. X            myname);
  287. X            warnings++;
  288. X        }
  289. X        else
  290. X        {
  291. X            displays = i;
  292. X        }
  293. X        break;
  294.  
  295. X        case 's':
  296. X        if ((delay = atoi(optarg)) < 0)
  297. X        {
  298. X            fprintf(stderr,
  299. X            "%s: warning: seconds delay should be non-negative -- using default\n",
  300. X            myname);
  301. X            delay = Default_DELAY;
  302. X            warnings++;
  303. X        }
  304. X        break;
  305.  
  306. X        default:
  307. X        fprintf(stderr,
  308. X            "Usage: %s [-Sbinu] [-d x] [-s x] [number]\n",
  309. X            myname);
  310. X        exit(1);
  311. X    }
  312. X    }
  313.  
  314. X    /* get count of top processes to display (if any) */
  315. X    if (optind < argc)
  316. X    {
  317. X    if ((topn = atoiwi(argv[optind])) == Invalid)
  318. X    {
  319. X        fprintf(stderr,
  320. X        "%s: warning: process display count should be non-negative -- using default\n",
  321. X        myname);
  322. X        topn = Default_TOPN;
  323. X        warnings++;
  324. X    }
  325. X    else
  326. X    {
  327. X        topn_specified = Yes;
  328. X    }
  329. X    }
  330.  
  331. X    /* initialize the kernel memory interface */
  332. X    init_kernel();
  333.  
  334. X    if (initialized != 1)
  335. X    {
  336. X    /* get the list of symbols we want to access in the kernel */
  337. X    /* errno = 0; ??? */
  338. X    nlist(VMUNIX, nlst);
  339. X    if (nlst[0].n_type == 0)
  340. X    {
  341. X        fprintf(stderr, "%s: can't nlist image\n", VMUNIX);
  342. X        exit(2);
  343. X    }
  344. X    
  345. X    /* get the symbol values out of kmem */
  346. X    getkval(nlst[X_PROC].n_value,  &proc,  sizeof(int),
  347. X        nlst[X_PROC].n_name);
  348. X    getkval(nlst[X_NPROC].n_value, &nproc, sizeof(int),
  349. X        nlst[X_NPROC].n_name);
  350. X    getkval(nlst[X_HZ].n_value,    &hz,    sizeof(int),
  351. X        nlst[X_HZ].n_name);
  352. X    getkval(nlst[X_CCPU].n_value,  &ccpu,  sizeof(int),
  353. X        nlst[X_CCPU].n_name);
  354. X    
  355. X    /* some calculations we use later */
  356. X    
  357. X    mpid_offset = nlst[X_MPID].n_value;
  358. X    avenrun_offset = nlst[X_AVENRUN].n_value;
  359. X    cp_time_offset = nlst[X_CP_TIME].n_value;
  360. X    total_offset = nlst[X_TOTAL].n_value;
  361. X    
  362. X    /* this is used in calculating WCPU -- calculate it ahead of time */
  363. X#ifdef sun
  364. X    logcpu = log((double)ccpu / FSCALE);
  365. X#else
  366. X    logcpu = log(ccpu);
  367. X#endif
  368. X    
  369. X    /* allocate space for proc structure array and array of pointers */
  370. X    bytes  = nproc * sizeof(struct proc);
  371. X    pbase  = (struct proc *)sbrk(bytes);
  372. X    pref   = (struct proc **)sbrk(nproc * sizeof(struct proc *));
  373.  
  374. X    /* Just in case ... */
  375. X    if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
  376. X    {
  377. X        fprintf(stderr, "%s: can't allocate sufficient memory\n", myname);
  378. X        exit(3);
  379. X    }
  380. X    
  381. X    /* initialize the hashing stuff */
  382. X    if (do_unames)
  383. X    {
  384. X        init_hash();
  385. X    }
  386. X    
  387. X    if (do_init)
  388. X    {
  389. X        initialized = 1;
  390. X        kill(0, SIGQUIT);
  391. X        exit(99);
  392. X    }
  393. X    }
  394.  
  395. X    /* initialize termcap */
  396. X    init_termcap();
  397.  
  398. X    /*
  399. X     *  Smart terminals can only display so many processes, precisely
  400. X     *    "screen_length - Header_lines".  When run on dumb terminals, nothing
  401. X     *    fancy is done anyway, so we can display as many processes as the
  402. X     *    system can make.  But since we never need to remember what is on the
  403. X     *    screen, we only allocate a buffer for one screen line.
  404. X     */
  405. X    if (smart_terminal)
  406. X    {
  407. X    /* can only display (screen_length - Header_lines) processes */
  408. X    i = screen_length - Header_lines;
  409. X    if (topn > i)        /* false even when topn == Infinity */
  410. X    {
  411. X        fprintf(stderr,
  412. X        "%s: warning: this terminal can only display %d processes.\n",
  413. X        myname, screen_length - Header_lines);
  414. X        topn = i;
  415. X        warnings++;
  416. X    }
  417. X    }
  418. X    else
  419. X    {
  420. X    i = 1;
  421. X    screen_length = nproc + Header_lines;
  422. X    }
  423.  
  424. X    /* allocate space for the screen buffer */
  425. X    screenbuf = (char (*)[])sbrk(i * Display_width);
  426. X    if (screenbuf == (char (*)[])NULL)
  427. X    {
  428. X    fprintf(stderr, "%s: can't allocate sufficient memory\n", myname);
  429. X    exit(4);
  430. X    }
  431.  
  432. X    /* adjust for topn == Infinity */
  433. X    if (topn == Infinity)
  434. X    {
  435. X    /*
  436. X     *  For smart terminals, infinity really means everything that can
  437. X     *  be displayed (which just happens to be "i" at this point).
  438. X     *  On dumb terminals, infinity means every process in the system!
  439. X     *  We only really want to do that if it was explicitly specified.
  440. X     *  This is always the case when "Default_TOPN != Infinity".  But if
  441. X     *  topn wasn't explicitly specified and we are on a dumb terminal
  442. X     *  and the default is Infinity, then (and only then) we use
  443. X     *  "Nominal_TOPN" instead.
  444. X     */
  445. X#if Default_TOPN == Infinity
  446. X    topn = smart_terminal ? i :
  447. X            (topn_specified ? nproc : Nominal_TOPN);
  448. X#else
  449. X    topn = smart_terminal ? i : nproc;
  450. X#endif
  451. X    }
  452.  
  453. X    /* determine interactive state */
  454. X    if (interactive == Maybe)
  455. X    {
  456. X    interactive = smart_terminal;
  457. X    }
  458.  
  459. X    /* if # of displays not specified, fill it in */
  460. X    if (displays == 0)
  461. X    {
  462. X    displays = smart_terminal ? Infinity : 1;
  463. X    }
  464.  
  465. X    /* hold interrupt signals while setting up the screen and the handlers */
  466. X#ifndef FOUR_ONE
  467. X    old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP));
  468. X#endif
  469. X    init_screen();
  470. X    signal(SIGINT, leave);
  471. X    signal(SIGQUIT, leave);
  472. X    signal(SIGTSTP, tstop);
  473. X#ifndef FOUR_ONE
  474. X    sigsetmask(old_sigmask);
  475. X#endif
  476. X    if (warnings)
  477. X    {
  478. X    fprintf(stderr, "....");
  479. X    fflush(stderr);            /* why must I do this? */
  480. X    sleep(3 * warnings);
  481. X    }
  482. X    clear();
  483.  
  484. X    /* setup the jump buffer for stops */
  485. X    if (setjmp(jmp_int) != 0)
  486. X    {
  487. X    /* control ends up here after an interrupt */
  488. X    clear();
  489. X    reset_display();
  490. X    }
  491.  
  492. X    /*
  493. X     *  main loop -- repeat while display count is positive or while it
  494. X     *        indicates infinity (by being -1)
  495. X     */
  496.  
  497. X    while ((displays == -1) || (displays-- > 0))
  498. X    {
  499. X    /* read all the proc structures in one fell swoop */
  500. X    getkval(proc, pbase, bytes, "proc array");
  501.  
  502. X    /* get the cp_time array */
  503. X    getkval(cp_time_offset, cp_time, sizeof(cp_time), "_cp_time");
  504.  
  505. X    /* get load average array */
  506. X    getkval(avenrun_offset, avenrun, sizeof(avenrun), "_avenrun");
  507.  
  508. X    /* get mpid -- process id of last process */
  509. X    getkval(mpid_offset, &mpid, sizeof(mpid), "_mpid");
  510.  
  511. X    /* get total -- systemwide main memory usage structure */
  512. X    getkval(total_offset, &total, sizeof(total), "_total");
  513.  
  514. X    /* count up process states and get pointers to interesting procs */
  515. X    total_procs = 0;
  516. X    active_procs = 0;
  517. X    bzero(proc_brkdn, sizeof(proc_brkdn));
  518. X    prefp = pref;
  519. X    for (pp = pbase, i = 0; i < nproc; pp++, i++)
  520. X    {
  521. X        /*
  522. X         *  Place pointers to each valid proc structure in pref[].
  523. X         *  Process slots that are actually in use have a non-zero
  524. X         *  status field.  Processes with SSYS set are system
  525. X         *  processes---these get ignored unless show_sysprocs is set.
  526. X         */
  527. X        if (pp->p_stat != 0 &&
  528. X        (show_sysprocs || ((pp->p_flag & SSYS) == 0)))
  529. X        {
  530. X        total_procs++;
  531. X        proc_brkdn[pp->p_stat]++;
  532. X        if (pp->p_stat != SZOMB)
  533. X        {
  534. X            *prefp++ = pp;
  535. X            active_procs++;
  536. X        }
  537. X        }
  538. X    }
  539.  
  540. X    /* display the load averages */
  541. X    (*d_loadave)(mpid, avenrun);
  542.  
  543. X    /*
  544. X     *  Display the current time.
  545. X     *  "ctime" always returns a string that looks like this:
  546. X     *  
  547. X     *    Sun Sep 16 01:03:52 1973
  548. X     *      012345678901234567890123
  549. X     *              1         2
  550. X     *
  551. X     *  We want indices 11 thru 18 (length 8).
  552. X     */
  553.  
  554. X    curr_time = time(0);
  555. X    if (smart_terminal)
  556. X    {
  557. X        Move_to(screen_width - 8, 0);
  558. X    }
  559. X    else
  560. X    {
  561. X        fputs("    ", stdout);
  562. X    }
  563. X    printf("%-8.8s\n", &(ctime(&curr_time)[11]));
  564.  
  565. X    /* display process state breakdown */
  566. X    (*d_procstates)(total_procs, proc_brkdn);
  567.  
  568. X    /* calculate percentage time in each cpu state */
  569. X    if (dostates)    /* but not the first time */
  570. X    {
  571. X        total_change = 0;
  572. X        for (i = 0; i < CPUSTATES; i++)
  573. X        {
  574. X        /* calculate changes for each state and overall change */
  575. X        if (cp_time[i] < cp_old[i])
  576. X        {
  577. X            /* this only happens when the counter wraps */
  578. X            change = (int)
  579. X            ((unsigned long)cp_time[i]-(unsigned long)cp_old[i]);
  580. X        }
  581. X        else
  582. X        {
  583. X            change = cp_time[i] - cp_old[i];
  584. X        }
  585. X        total_change += (cp_change[i] = change);
  586. X        cp_old[i] = cp_time[i];
  587. X        }
  588. X        (*d_cpustates)(cp_change, total_change);
  589. X    }
  590. X    else
  591. X    {
  592. X        /* we'll do it next time */
  593. X        if (smart_terminal)
  594. X        {
  595. X        z_cpustates();
  596. X        }
  597. X        else
  598. X        {
  599. X        putchar('\n');
  600. X        }
  601. X        dostates = Yes;
  602. X        bzero(cp_old, sizeof(cp_old));
  603. X    }
  604.  
  605. X    /* display main memory statistics */
  606. X    (*d_memory)(
  607. X        pagetok(total.t_rm), pagetok(total.t_arm),
  608. X        pagetok(total.t_vm), pagetok(total.t_avm),
  609. X        pagetok(total.t_free));
  610.  
  611. X    i = 0;
  612. X    if (topn > 0)
  613. X    {
  614. X        /* update the header area */
  615. X        (*d_header)(uname_field);
  616. X    
  617. X        /* sort by cpu percentage (pctcpu) */
  618. X        qsort(pref, active_procs, sizeof(struct proc *), proc_compar);
  619. X    
  620. X        /* adjust for a lack of processes */
  621. X        if (active_procs > topn)
  622. X        {
  623. X        active_procs = topn;
  624. X        }
  625.  
  626. X        /*
  627. X         *  Now, show the top "n" processes.  The method is slightly
  628. X         *    different for dumb terminals, so we will just use two very
  629. X         *    similar loops; this increases speed but also code size.
  630. X         */
  631. X        if (smart_terminal)
  632. X        {
  633. X        for (prefp = pref, i = 0; i < active_procs; prefp++, i++)
  634. X        {
  635. X            pp = *prefp;
  636. X            (*d_process)(i, pp, get_userid);
  637. X        }
  638. X        }
  639. X        else for (prefp = pref, i = 0; i < active_procs; prefp++, i++)
  640. X        {
  641. X        pp = *prefp;
  642. X        /* (only one buffer lien with dumb terminals) */
  643. X        (*d_process)(0, pp, get_userid);
  644. X        }
  645. X    }
  646.  
  647. X    /* do end-screen processing */
  648. X    u_endscreen(i);
  649.  
  650. X    /* now, flush the output buffer */
  651. X    fflush(stdout);
  652.  
  653. X    /* only do the rest if we have more displays to show */
  654. X    if (displays)
  655. X    {
  656. X        /* switch out for new display on smart terminals */
  657. X        if (smart_terminal)
  658. X        {
  659. X        d_loadave = u_loadave;
  660. X        d_procstates = u_procstates;
  661. X        d_cpustates = u_cpustates;
  662. X        d_memory = u_memory;
  663. X        d_header = u_header;
  664. X        d_process = u_process;
  665. X        }
  666. X    
  667. X#ifndef FOUR_ONE
  668. X        if (!interactive)
  669. X#endif
  670. X        {
  671. X        /* set up alarm */
  672. X        signal(SIGALRM, onalrm);
  673. X        alarm(delay);
  674. X    
  675. X        /* wait for the rest of it .... */
  676. X        pause();
  677. X        }
  678. X#ifndef FOUR_ONE
  679. X        else
  680. X        {
  681. X        /* wait for either input or the end of the delay period */
  682. X        readfds = 1;            /* for standard input */
  683. X        timeout.tv_sec  = delay;
  684. X        timeout.tv_usec = 0;
  685. X        if (select(32, &readfds, 0, 0, &timeout) > 0)
  686. X        {
  687. X            int newval;
  688. X            char *errmsg;
  689. X    
  690. X            /* something to read -- clear the message area first */
  691. X            if (msg_showing)
  692. X            {
  693. X            if (smart_terminal)
  694. X            {
  695. X                putcap(clear_line);
  696. X            }
  697. X            msg_showing = No;
  698. X            }
  699.  
  700. X            /* now read it and act on it */
  701. X            read(0, &ch, 1);
  702. X            switch(ch)
  703. X            {
  704. X            case '\f':        /* redraw screen */
  705. X                reset_display();
  706. X                clear();
  707. X                break;
  708.  
  709. X            case ' ':        /* merely update display */
  710. X                break;
  711. X    
  712. X            case 'q':        /* quit */
  713. X                quit(0);
  714. X                break;
  715. X    
  716. X            case 'h':        /* help */
  717. X            case '?':
  718. X                reset_display();
  719. X                clear();
  720. X                show_help();
  721. X                standout("Hit any key to continue: ");
  722. X                fflush(stdout);
  723. X                    read(0, &ch, 1);
  724. X                clear();
  725. X                break;
  726. X    
  727. X            case 'e':        /* show errors */
  728. X                if (error_count() == 0)
  729. X                {
  730. X                standout(" Currently no errors to report.");
  731. X                msg_showing = Yes;
  732. X                }
  733. X                else
  734. X                {
  735. X                reset_display();
  736. X                clear();
  737. X                show_errors();
  738. X                standout("Hit any key to continue: ");
  739. X                fflush(stdout);
  740. X                read(0, &ch, 1);
  741. X                clear();
  742. X                }
  743. X                break;
  744. X    
  745. X            case 'n':        /* new number */
  746. X            case '#':
  747. X                standout("Number of processes to show: ");
  748. X                newval = readline(tempbuf1, 8, Yes);
  749. X                putchar('\r');
  750. X                if (newval > -1)
  751. X                {
  752. X                if (newval > (i = screen_length - Header_lines))
  753. X                {
  754. X                    standout(
  755. X                      " This terminal can only display %d processes.",
  756. X                      i);
  757. X                    newval = i;
  758. X                    msg_showing = Yes;
  759. X                    break;
  760. X                }
  761. X    
  762. X                if (newval > topn)
  763. X                {
  764. X                    /* zero fill appropriate part of screenbuf */
  765. X                    bzero(screenbuf[topn],
  766. X                    (newval - topn) * Display_width);
  767. X    
  768. X                    /* redraw header if need be */
  769. X                    if (topn == 0)
  770. X                    {
  771. X                    d_header = i_header;
  772. X                    }
  773. X                }
  774. X                topn = newval;
  775. X                }
  776. X                putcap(clear_line);
  777. X                break;
  778. X    
  779. X            case 's':        /* new seconds delay */
  780. X                standout("Seconds to delay: ");
  781. X                if ((i = readline(tempbuf1, 8, Yes)) > -1)
  782. X                {
  783. X                delay = i;
  784. X                }
  785. X                putchar('\r');
  786. X                putcap(clear_line);
  787. X                break;
  788. X    
  789. X            case 'd':        /* change display count */
  790. X                standout("Displays to show (currently %s): ",
  791. X                    displays == -1 ? "infinite" :
  792. X                             itoa(displays));
  793. X                if ((i = readline(tempbuf1, 10, Yes)) > 0)
  794. X                {
  795. X                displays = i;
  796. X                }
  797. X                else if (i == 0)
  798. X                {
  799. X                quit(0);
  800. X                }
  801. X                putchar('\r');
  802. X                putcap(clear_line);
  803. X                break;
  804.  
  805. X            case 'k':        /* kill program */
  806. X                fputs("kill ", stdout);
  807. X                if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
  808. X                {
  809. X                if ((errmsg = kill_procs(tempbuf2)) != NULL)
  810. X                {
  811. X                    putchar('\r');
  812. X                    standout(errmsg);
  813. X                }
  814. X                msg_showing = Yes;
  815. X                }
  816. X                else
  817. X                {
  818. X                putchar('\r');
  819. X                }
  820. X                putcap(clear_line);
  821. X                break;
  822. X    
  823. X            case 'r':        /* renice program */
  824. X                fputs("renice ", stdout);
  825. X                if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
  826. X                {
  827. X                if ((errmsg = renice_procs(tempbuf2)) != NULL)
  828. X                {
  829. X                    putchar('\r');
  830. X                    standout(errmsg);
  831. X                    msg_showing = Yes;
  832. X                }
  833. X                }
  834. X                else
  835. X                {
  836. X                putchar('\r');
  837. X                }
  838. X                putcap(clear_line);
  839. X                break;
  840. X    
  841. X            default:
  842. X                standout(" Command not understood");
  843. X                msg_showing = Yes;
  844. X            }
  845. X        }
  846. X        else if (msg_showing)
  847. X        {
  848. X            if (smart_terminal)
  849. X            {
  850. X            putcap(clear_line);
  851. X            }
  852. X            msg_showing = No;
  853. X        }
  854. X        }
  855. X#endif
  856. X    }
  857. X    }
  858.  
  859. X    quit(0);
  860. X}
  861.  
  862. X/*
  863. X *  reset_display() - reset all the display routine pointers so that entire
  864. X *    screen will get redrawn.
  865. X */
  866.  
  867. Xreset_display()
  868.  
  869. X{
  870. X    d_loadave    = i_loadave;
  871. X    d_procstates = i_procstates;
  872. X    d_cpustates  = i_cpustates;
  873. X    d_memory     = i_memory;
  874. X    d_header     = i_header;
  875. X    d_process     = i_process;
  876. X}
  877.  
  878. Xreadline(buffer, size, numeric)
  879.  
  880. Xchar *buffer;
  881. Xint  size;
  882. Xint  numeric;
  883.  
  884. X{
  885. X    register char *ptr = buffer;
  886. X    register char ch;
  887. X    register char cnt = 0;
  888.  
  889. X    size -= 1;
  890. X    while ((fflush(stdout), read(0, ptr, 1) > 0))
  891. X    {
  892. X    if ((ch = *ptr) == '\n')
  893. X    {
  894. X        break;
  895. X    }
  896.  
  897. X    if (ch == ch_kill)
  898. X    {
  899. X        *buffer = '\0';
  900. X        return(-1);
  901. X    }
  902. X    else if (ch == ch_erase)
  903. X    {
  904. X        if (cnt <= 0)
  905. X        {
  906. X        putchar('\7');
  907. X        }
  908. X        else
  909. X        {
  910. X        fputs("\b \b", stdout);
  911. X        ptr--;
  912. X        cnt--;
  913. X        }
  914. X    }
  915. X    else if (cnt == size || (numeric && (ch < '0' || ch > '9')))
  916. X    {
  917. X        putchar('\7');
  918. X    }
  919. X    else
  920. X    {
  921. X        putchar(ch);
  922. X        ptr++;
  923. X        cnt++;
  924. X    }
  925. X    }
  926. X    *ptr = '\0';
  927. X    return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
  928. X}
  929.  
  930. X/*
  931. X *  signal handlers
  932. X */
  933.  
  934. Xleave()            /* exit under normal conditions -- INT handler */
  935.  
  936. X{
  937. X    end_screen();
  938. X    exit(0);
  939. X}
  940.  
  941. Xtstop()
  942.  
  943. X{
  944. X    /* move to the lower left */
  945. X    end_screen();
  946. X    fflush(stdout);
  947.  
  948. X#ifdef FOUR_ONE        /* a 4.1 system */
  949.  
  950. X    /* send a STOP (uncatchable) to everyone in the process group */
  951. X    kill(0, SIGSTOP);
  952.  
  953. X    /* reset the signal handler */
  954. X    signal(SIGTSTP, tstop);
  955.  
  956. X#else            /* assume it is a 4.2 system */
  957.  
  958. X    /* default the signal handler action */
  959. X    signal(SIGTSTP, SIG_DFL);
  960.  
  961. X    /* unblock the signal and send ourselves one */
  962. X    sigsetmask(sigblock(0) & ~(1 << (SIGTSTP - 1)));
  963. X    kill(0, SIGTSTP);
  964.  
  965. X    /* reset the signal handler */
  966. X    signal(SIGTSTP, tstop);
  967.  
  968. X#endif
  969. X    /* reinit screen */
  970. X    reinit_screen();
  971.  
  972. X    /* jump to appropriate place */
  973. X    longjmp(jmp_int, 1);
  974.  
  975. X    /*NOTREACHED*/
  976. X}
  977.  
  978. Xquit(status)        /* exit under duress */
  979.  
  980. Xint status;
  981.  
  982. X{
  983. X    end_screen();
  984. X    exit(status);
  985. X}
  986.  
  987. Xonalrm()
  988.  
  989. X{
  990. X    return(0);
  991. X}
  992.  
  993. X/*
  994. X *  proc_compar - comparison function for "qsort"
  995. X *    Compares the resource consumption of two processes using five
  996. X *      distinct keys.  The keys (in descending order of importance) are:
  997. X *      percent cpu, cpu ticks, state, resident set size, total virtual
  998. X *      memory usage.  The process states are ordered as follows (from least
  999. X *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  1000. X *      array declaration below maps a process state index into a number
  1001. X *      that reflects this ordering.
  1002. X */
  1003.  
  1004. Xunsigned char sorted_state[] =
  1005. X{
  1006. X    0,    /* not used        */
  1007. X    3,    /* sleep        */
  1008. X    1,    /* ABANDONED (WAIT)    */
  1009. X    6,    /* run            */
  1010. X    5,    /* start        */
  1011. X    2,    /* zombie        */
  1012. X    4    /* stop            */
  1013. X};
  1014. Xproc_compar(pp1, pp2)
  1015.  
  1016. Xstruct proc **pp1;
  1017. Xstruct proc **pp2;
  1018.  
  1019. X{
  1020. X    register struct proc *p1;
  1021. X    register struct proc *p2;
  1022. X    register int result;
  1023. X#ifndef sun
  1024. X    register double dresult;
  1025. X#endif
  1026.  
  1027. X    /* remove one level of indirection */
  1028. X    p1 = *pp1;
  1029. X    p2 = *pp2;
  1030.  
  1031. X    /* compare percent cpu (pctcpu) */
  1032. X#ifdef sun
  1033. X    if ((result = p2->p_pctcpu - p1->p_pctcpu) == 0)
  1034. X#else
  1035. X    if ((dresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
  1036. X#endif
  1037. X    {
  1038. X    /* use cpticks to break the tie */
  1039. X    if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
  1040. X    {
  1041. X        /* use process state to break the tie */
  1042. X        if ((result = sorted_state[p2->p_stat] -
  1043. X              sorted_state[p1->p_stat])  == 0)
  1044. X        {
  1045. X        /* use priority to break the tie */
  1046. X        if ((result = p2->p_pri - p1->p_pri) == 0)
  1047. X        {
  1048. X            /* use resident set size (rssize) to break the tie */
  1049. X            if ((result = p2->p_rssize - p1->p_rssize) == 0)
  1050. X            {
  1051. X            /* use total memory to break the tie */
  1052. X#ifdef pyr
  1053. X            result = (p2->p_tsize + p2->p_dsize + p2->p_ussize) -
  1054. X                 (p1->p_tsize + p1->p_dsize + p1->p_ussize);
  1055. X#else
  1056. X            result = (p2->p_tsize + p2->p_dsize + p2->p_ssize) -
  1057. X                 (p1->p_tsize + p1->p_dsize + p1->p_ssize);
  1058. X#endif
  1059. X            }
  1060. X        }
  1061. X        }
  1062. X    }
  1063. X    }
  1064. X#ifndef sun
  1065. X    else
  1066. X    {
  1067. X    result = dresult < 0.0 ? -1 : 1;
  1068. X    }
  1069. X#endif
  1070.  
  1071. X    return(result);
  1072. X}
  1073.  
  1074. X/* routines to translate uids into a string */
  1075.  
  1076. Xchar *user_name(euid, ruid)
  1077.  
  1078. Xint euid, ruid;
  1079.  
  1080. X{
  1081. X    return(username(euid));
  1082. X}
  1083.  
  1084. Xchar *user_uid(euid, ruid)
  1085.  
  1086. Xint euid, ruid;
  1087.  
  1088. X{
  1089. X    return(itoa7(euid));
  1090. X}
  1091.  
  1092. X/*
  1093. X *  These routines handle uid to username mapping.
  1094. X *  They use a hashing table scheme to reduce reading overhead.
  1095. X */
  1096.  
  1097. Xstruct hash_el {
  1098. X    int  uid;
  1099. X    char name[8];
  1100. X};
  1101.  
  1102. X#define    H_empty    -1
  1103.  
  1104. X/* simple minded hashing function */
  1105. X#define    hashit(i)    ((i) % Table_size)
  1106.  
  1107. Xstruct hash_el hash_table[Table_size];
  1108.  
  1109. Xinit_hash()
  1110.  
  1111. X{
  1112. X    register int i;
  1113. X    register struct hash_el *h;
  1114.  
  1115. X    for (h = hash_table, i = 0; i < Table_size; h++, i++)
  1116. X    {
  1117. X    h->uid = H_empty;
  1118. X    }
  1119. X}
  1120.  
  1121. Xchar *username(uid)
  1122.  
  1123. Xregister int uid;
  1124.  
  1125. X{
  1126. X    register int index;
  1127. X    register int found;
  1128. X    register char *name;
  1129.  
  1130. X    /* This is incredibly naive, but it'll probably get changed anyway */
  1131. X    index = hashit(uid);
  1132. X    while ((found = hash_table[index].uid) != uid)
  1133. X    {
  1134. X    if (found == H_empty)
  1135. X    {
  1136. X        /* not here -- get it out of passwd */
  1137. X        index = get_user(uid);
  1138. X        break;        /* out of while */
  1139. X    }
  1140. X    index = (index + 1) % Table_size;
  1141. X    }
  1142. X    return(hash_table[index].name);
  1143. X}
  1144.  
  1145. Xenter_user(uid, name)
  1146.  
  1147. Xregister int  uid;
  1148. Xregister char *name;
  1149.  
  1150. X{
  1151. X    register int length;
  1152. X    register int index;
  1153. X    register int try;
  1154. X    static int uid_count = 0;
  1155.  
  1156. X    /* avoid table overflow -- insure at least one empty slot */
  1157. X    if (++uid_count >= Table_size)
  1158. X    {
  1159. X    fprintf(stderr, "table overflow: too many users\n");
  1160. X    quit(10);
  1161. X    }
  1162.  
  1163. X    index = hashit(uid);
  1164. X    while ((try = hash_table[index].uid) != H_empty)
  1165. X    {
  1166. X    if (try == uid)
  1167. X    {
  1168. X        return(index);
  1169. X    }
  1170. X    index = (index + 1) % Table_size;
  1171. X    }
  1172. X    hash_table[index].uid = uid;
  1173. X    strncpy(hash_table[index].name, name, 8);
  1174. X    return(index);
  1175. X}
  1176.  
  1177. Xget_user(uid)
  1178.  
  1179. Xregister int uid;
  1180.  
  1181. X{
  1182. X    struct passwd *pwd;
  1183. X    register int last_index;
  1184.  
  1185. X    while ((pwd = getpwent()) != NULL)
  1186. X    {
  1187. X    last_index = enter_user(pwd->pw_uid, pwd->pw_name);
  1188. X    if (pwd->pw_uid == uid)
  1189. X    {
  1190. X        return(last_index);
  1191. X    }
  1192. X    }
  1193. X    return(enter_user(uid, itoa7(uid)));
  1194. X}
  1195.  
  1196. Xatoiwi(str)
  1197.  
  1198. Xchar *str;
  1199.  
  1200. X{
  1201. X    register int len;
  1202.  
  1203. X    len = strlen(str);
  1204. X    if (len != 0)
  1205. X    {
  1206. X    if (strncmp(str, "infinity", len) == 0 ||
  1207. X        strncmp(str, "all",      len) == 0 ||
  1208. X        strncmp(str, "maximum",  len) == 0)
  1209. X    {
  1210. X        return(Infinity);
  1211. X    }
  1212. X    else if (str[0] == '-')
  1213. X    {
  1214. X        return(Invalid);
  1215. X    }
  1216. X    else
  1217. X    {
  1218. X        return(atoi(str));
  1219. X    }
  1220. X    }
  1221. X    return(0);
  1222. X}
  1223.  
  1224. X/*
  1225. X *  itoa - convert integer (decimal) to ascii string for positive numbers
  1226. X *         only (we don't bother with negative numbers since we know we
  1227. X *       don't use them).
  1228. X */
  1229.  
  1230. Xstatic char buffer[16];        /* shared by the next two routines */
  1231.  
  1232. Xchar *itoa(val)
  1233.  
  1234. Xregister int val;
  1235.  
  1236. X{
  1237. X    register char *ptr;
  1238.  
  1239. X    ptr = buffer + sizeof(buffer);
  1240. X    *--ptr = '\0';
  1241. X    if (val == 0)
  1242. X    {
  1243. X    *--ptr = '0';
  1244. X    }
  1245. X    else while (val != 0)
  1246. X    {
  1247. X    *--ptr = (val % 10) + '0';
  1248. X    val /= 10;
  1249. X    }
  1250. X    return(ptr);
  1251. X}
  1252.  
  1253. X/*
  1254. X *  itoa7(val) - like itoa, except the number is right justified in a 7
  1255. X *    character field.  This code is a duplication of itoa instead of
  1256. X *    a front end to a more general routine for efficiency.
  1257. X */
  1258.  
  1259. Xchar *itoa7(val)
  1260.  
  1261. Xregister int val;
  1262.  
  1263. X{
  1264. X    register char *ptr;
  1265.  
  1266. X    ptr = buffer + sizeof(buffer);
  1267. X    *--ptr = '\0';
  1268. X    if (val == 0)
  1269. X    {
  1270. X    *--ptr = '0';
  1271. X    }
  1272. X    else while (val != 0)
  1273. X    {
  1274. X    *--ptr = (val % 10) + '0';
  1275. X    val /= 10;
  1276. X    }
  1277. X    while (ptr > buffer + sizeof(buffer) - 7)
  1278. X    {
  1279. X    *--ptr = ' ';
  1280. X    }
  1281. X    return(ptr);
  1282. X}
  1283.  
  1284. @//E*O*F top.c//
  1285. chmod u=rw,g=rw,o=rw $OUT
  1286.  
  1287. echo x - top.local.h
  1288. if test -f top.local.h ; then
  1289.     echo top.local.h exists, putting output in $$top.local.h
  1290.     OUT=$$top.local.h
  1291.     STATUS=1
  1292. else
  1293.     OUT=top.local.h
  1294. fi
  1295. sed 's/^X//' > $OUT <<'@//E*O*F top.local.h//'
  1296. X/*
  1297. X *  Top - a top users display for Berkeley Unix
  1298. X *
  1299. X *  Definitions for things that might vary between installations.
  1300. X */
  1301.  
  1302. X/*
  1303. X *  "Table_size" defines the size of the hash tables used to map uid to
  1304. X *  username.  The number of users in /etc/passwd CANNOT be greater than
  1305. X *  this number.  If the error message "table overflow: too many users"
  1306. X *  is printed by top, then "Table_size" needs to be increased.  Things will
  1307. X *  work best if the number is a prime number that is about twice the number
  1308. X *  of lines in /etc/passwd.
  1309. X */
  1310. X#ifndef Table_size
  1311. X#define Table_size    421
  1312. X#endif
  1313.  
  1314. X/*
  1315. X *  "Nominal_TOPN" is used as the default TOPN when Default_TOPN is Infinity
  1316. X *  and the output is a dumb terminal.  If we didn't do this, then
  1317. X *  installations who use a default TOPN of Infinity will get every
  1318. X *  process in the system when running top on a dumb terminal (or redirected
  1319. X *  to a file).  Note that Nominal_TOPN is a default:  it can still be
  1320. X *  overridden on the command line, even with the value "infinity".
  1321. X */
  1322. X#ifndef Nominal_TOPN
  1323. X#define Nominal_TOPN    18
  1324. X#endif
  1325.  
  1326. X/*
  1327. X *  File name for the system image and the memory devices.
  1328. X */
  1329. X#define VMUNIX    "/vmunix"
  1330. X#define KMEM    "/dev/kmem"
  1331. X#define MEM    "/dev/mem"
  1332. @//E*O*F top.local.h//
  1333. chmod u=rw,g=rw,o=rw $OUT
  1334.  
  1335. echo x - top.man
  1336. if test -f top.man ; then
  1337.     echo top.man exists, putting output in $$top.man
  1338.     OUT=$$top.man
  1339.     STATUS=1
  1340. else
  1341.     OUT=top.man
  1342. fi
  1343. sed 's/^X//' > $OUT <<'@//E*O*F top.man//'
  1344. X.\" NOTE:  changes to the manual page for "top" should be made in the
  1345. X.\"        file "top.man" and NOT in the file "top.1".
  1346. X.TH TOP 1 Local
  1347. X.UC 4
  1348. X.SH NAME
  1349. Xtop \- display and update information about the top cpu processes
  1350. X.SH SYNOPSIS
  1351. X.B top
  1352. X[
  1353. X.B \-Sbinu
  1354. X] [
  1355. X.BI \-d count
  1356. X] [
  1357. X.BI \-s time
  1358. X] [
  1359. X.I number
  1360. X]
  1361. X.SH DESCRIPTION
  1362. X.\" This defines appropriate quote strings for nroff and troff
  1363. X.ds lq \&"
  1364. X.ds rq \&"
  1365. X.if t .ds lq ``
  1366. X.if t .ds rq ''
  1367. X.\" Just in case these number registers aren't set yet...
  1368. X.if \nN==0 .nr N 10
  1369. X.if \nD==0 .nr D 5
  1370. X.I Top
  1371. Xdisplays the top
  1372. X.if !\nN==-1 \nN
  1373. Xprocesses on the system and periodically updates this information.
  1374. X.if \nN==-1 \
  1375. X\{\
  1376. XIf standard output is an intelligent terminal (see below) then
  1377. Xas many processes as will fit on the terminal screen are displayed
  1378. Xby default.  Otherwise, a good number of them are shown (around 20).
  1379. X.\}
  1380. XRaw cpu percentage is used to rank the processes.  If
  1381. X.I number
  1382. Xis given, then the top
  1383. X.I number
  1384. Xprocesses will be displayed instead of the default.
  1385. X.PP
  1386. X.I Top
  1387. Xmakes a distinction between terminals that support advanced capabilities
  1388. Xand those that do not.  This
  1389. Xdistinction affects the choice of defaults for certain options.  In the
  1390. Xremainder of this document, an \*(lqintelligent\*(rq terminal is one that
  1391. Xsupports cursor addressing, clear screen, and clear to end of line.
  1392. XConversely, a \*(lqdumb\*(rq terminal is one that does not support such
  1393. Xfeatures.  If the output of
  1394. X.I top
  1395. Xis redirected to a file, it acts as if it were being run on a dumb
  1396. Xterminal.
  1397. X.SH OPTIONS
  1398. X.TP
  1399. X.B \-S
  1400. XShow system processes in the display.  Normally, system processes such as
  1401. Xthe pager and the swapper are not shown.  This option makes them visible.
  1402. X.TP
  1403. X.B \-b
  1404. XUse \*(lqbatch\*(rq mode.  In this mode, all input from the terminal is
  1405. Xignored.  Interrupt characters (such as ^C and ^\e) still have an effect.
  1406. XThis is the default on a dumb terminal, or when the output is not a terminal.
  1407. X.TP
  1408. X.B \-i
  1409. XUse \*(lqinteractive\*(rq mode.  In this mode, any input is immediately
  1410. Xread for processing.  See the section on \*(lqInteractive Mode\*(rq
  1411. Xfor an explanation of
  1412. Xwhich keys perform what functions.  After the command is processed, the
  1413. Xscreen will immediately be updated, even if the command was not
  1414. Xunderstood.  This mode is the default when standard output is an
  1415. Xintelligent terminal.
  1416. X.TP
  1417. X.B \-n
  1418. XUse \*(lqnon-interactive\*(rq mode.  This is indentical to \*(lqbatch\*(rq
  1419. Xmode.
  1420. X.TP
  1421. X.B \-u
  1422. XDo not take the time to map uid numbers to usernames.  Normally,
  1423. X.I top
  1424. Xwill read as much of the file \*(lq/etc/passwd\*(rq as is necessary to map
  1425. Xall the user id numbers it encounters into login names.  This option
  1426. Xdisables all that, while possibly decreasing execution time.  The uid
  1427. Xnumbers are displayed instead of the names.
  1428. X.TP
  1429. X.BI \-d count
  1430. XShow only
  1431. X.I count
  1432. Xdisplays, then exit.  A display is considered to be one update of the
  1433. Xscreen.  This option allows the user to select the number of displays he
  1434. Xwants to see before
  1435. X.I top
  1436. Xautomatically exits.  For intelligent terminals, no upper limit
  1437. Xis set.  The default is 1 for dumb terminals.
  1438. X.TP
  1439. X.BI \-s time
  1440. XSet the delay between screen updates to
  1441. X.I time
  1442. Xseconds.  The default delay between updates is \nD seconds.
  1443. X.PP
  1444. XBoth
  1445. X.I count
  1446. Xand
  1447. X.I number
  1448. Xfields can be specified as \*(lqinfinite\*(rq, indicating that they can
  1449. Xstretch as far as possible.  This is accomplished by using any proper
  1450. Xprefix of the keywords
  1451. X\*(lqinfinity\*(rq,
  1452. X\*(lqmaximum\*(rq,
  1453. Xor
  1454. X\*(lqall\*(rq.
  1455. XThe default for
  1456. X.I count
  1457. Xon an intelligent terminal is, in fact,
  1458. X.BI infinity .
  1459. X.SH "INTERACTIVE MODE"
  1460. XWhen
  1461. X.I top
  1462. Xis running in \*(lqinteractive mode\*(rq, it reads commands from the
  1463. Xterminal and acts upon them accordingly.  In this mode, the terminal is
  1464. Xput in \*(lqCBREAK\*(rq, so that a character will be
  1465. Xprocessed as soon as it is typed.  Almost always, a key will be
  1466. Xpressed when
  1467. X.I top
  1468. Xis between displays; that is, while it is waiting for
  1469. X.I time
  1470. Xseconds to elapse.  If this is the case, the command will be
  1471. Xprocessed and the display will be updated immediately thereafter
  1472. X(reflecting any changes that the command may have specified).  This
  1473. Xhappens even if the command was incorrect.  If a key is pressed while 
  1474. X.I top
  1475. Xis in the middle of updating the display, it will finish the update and
  1476. Xthen process the command.  Some commands require additional information,
  1477. Xand the user will be prompted accordingly.  While typing this information
  1478. Xin, the user's erase and kill keys (as set up by the command
  1479. X.IR stty )
  1480. Xare recognized, and a newline terminates the input.
  1481. X.PP
  1482. XThese commands are currently recognized (^L refers to control-L):
  1483. X.TP
  1484. X.B ^L
  1485. XRedraw the screen.
  1486. X.IP "\fBh\fP\ or\ \fB?\fP"
  1487. XDisplay a summary of the commands (help screen).
  1488. X.TP
  1489. X.B q
  1490. XQuit
  1491. X.IR top.
  1492. X.TP
  1493. X.B d
  1494. XChange the number of displays to show (prompt for new number).
  1495. XRemember that the next display counts as one, so typing
  1496. X.B d1
  1497. Xwill make
  1498. X.I top
  1499. Xshow one final display and then immediately exit.
  1500. X.TP
  1501. X.B n or #
  1502. XChange the number of processes to display (prompt for new number).
  1503. X.TP
  1504. X.B s
  1505. XChange the number of seconds to delay between displays
  1506. X(prompt for new number).
  1507. X.TP
  1508. X.B k
  1509. XSend a signal (\*(lqkill\*(rq by default) to a list of processes.  This
  1510. Xacts similarly to the command
  1511. X.IR kill (1)).
  1512. X.TP
  1513. X.B r
  1514. XChange the priority (the \*(lqnice\*(rq) of a list of processes.
  1515. XThis acts similarly to the command
  1516. X.IR renice (8)).
  1517. X.TP
  1518. X.B e
  1519. XDisplay a list of system errors (if any) generated by the last
  1520. X.BR k ill
  1521. Xor
  1522. X.BR r enice
  1523. Xcommand.
  1524. X.SH "THE DISPLAY"
  1525. XThe top few lines of the display show general information
  1526. Xabout the state of the system, including
  1527. Xthe last process id assigned to a process,
  1528. Xthe three load averages,
  1529. Xthe current time,
  1530. Xthe number of existing processes,
  1531. Xthe number of processes in each state
  1532. X(sleeping, ABANDONED, running, starting, zombies, and stopped),
  1533. Xand a percentage of time spent in each of the processor states
  1534. X(user, nice, system, and idle).
  1535. XIt also includes the amount of virtual and real memory in use
  1536. X(with the amount of memory considered \*(lqactive\*(rq in parentheses) and
  1537. Xthe amount of free memory.
  1538. X.PP
  1539. XThe remainder of the screen displays information about individual
  1540. Xprocesses.  This display is similar in spirit to
  1541. X.IR ps (1)
  1542. Xbut it is not exactly the same.  PID is the process id, USERNAME is the name
  1543. Xof the process's owner (if
  1544. X.B \-u
  1545. Xis specified, a UID column will be substituted for USERNAME),
  1546. XPRI is the current priority of the process,
  1547. XNICE is the nice amount (in the range \-20 to 20),
  1548. XSIZE is the total size of the process (text, data, and stack),
  1549. XRES is the current amount of resident memory (both SIZE and RES are
  1550. Xgiven in kilobytes),
  1551. XSTATE is the current state (one of \*(lqsleep\*(rq, \*(lqWAIT\*(rq,
  1552. X\*(lqrun\*(rq, \*(lqidl\*(rq, \*(lqzomb\*(rq, or \*(lqstop\*(rq),
  1553. XTIME is the number of system and user cpu seconds that the process has used,
  1554. XWCPU is the weighted cpu percentage (this is the same value that
  1555. X.IR ps (1)
  1556. Xdisplays as CPU),
  1557. XCPU is the raw percentage and is the field that is sorted to determine
  1558. Xthe order of the processes, and
  1559. XCOMMAND is the name of the command that the process is currently running
  1560. X(if the process is swapped out, this column is marked \*(lq<swapped>\*(rq).
  1561. X.SH NOTES
  1562. XThe \*(lqABANDONED\*(rq state (known in the kernel as \*(lqSWAIT\*(rq) was
  1563. Xabandoned, thus the name.  A process should never end up in this state.
  1564. X.SH AUTHOR
  1565. XWilliam LeFebvre, Rice University graduate student
  1566. X.SH FILES
  1567. X.DT
  1568. X/dev/kmem        kernel memory
  1569. X.br
  1570. X/dev/mem        physical memory
  1571. X.br
  1572. X/etc/passwd        used to map uid numbers to user names
  1573. X.br
  1574. X/vmunix        system image
  1575. X.SH BUGS
  1576. XThe command name for swapped processes should be tracked down, but this
  1577. Xwould make the program run slower.
  1578. X.PP
  1579. XAs with
  1580. X.IR ps (1),
  1581. Xthings can change while
  1582. X.I top
  1583. Xis collecting information for an update.  The picture it gives is only a
  1584. Xclose approximation to reality.
  1585. X.SH "SEE ALSO"
  1586. Xkill(1),
  1587. Xps(1),
  1588. Xstty(1),
  1589. Xmem(4),
  1590. Xrenice(8)
  1591. @//E*O*F top.man//
  1592. chmod u=rw,g=rw,o=rw $OUT
  1593.  
  1594. echo x - MANIFEST
  1595. if test -f MANIFEST ; then
  1596.     echo MANIFEST exists, putting output in $$MANIFEST
  1597.     OUT=$$MANIFEST
  1598.     STATUS=1
  1599. else
  1600.     OUT=MANIFEST
  1601. fi
  1602. sed 's/^X//' > $OUT <<'@//E*O*F MANIFEST//'
  1603. XChanges                      1
  1604. XMANIFEST                     2
  1605. XMakefile                     1
  1606. XManifest                     1
  1607. XREADME                       1
  1608. Xboolean.h                    1
  1609. Xbzero.c                      1
  1610. Xcommands.c                   1
  1611. Xdisplay.c                    1
  1612. Xgetopt.c                     1
  1613. Xkernel.c                     1
  1614. Xlayout.h                     1
  1615. Xscreen.c                     1
  1616. Xscreen.h                     1
  1617. Xsigconv.awk                  1
  1618. Xtop.c                        2
  1619. Xtop.h                        1
  1620. Xtop.local.h                  2
  1621. Xtop.man                      2
  1622. @//E*O*F MANIFEST//
  1623. chmod u=rw,g=rw,o=rw $OUT
  1624.  
  1625. echo Inspecting for damage in transit...
  1626. temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
  1627. trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
  1628. cat > $temp <<\!!!
  1629.     1257    3700   26262 top.c
  1630.       36     209    1209 top.local.h
  1631.      247    1361    7861 top.man
  1632.       19      38     589 MANIFEST
  1633.     1559    5308   35921 total
  1634. !!!
  1635. wc  top.c top.local.h top.man MANIFEST | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
  1636. if test -s $dtemp ; then
  1637.     echo "Ouch [diff of wc output]:"
  1638.     cat $dtemp
  1639.     STATUS=1
  1640. elif test $STATUS = 0 ; then
  1641.     echo "No problems found."
  1642. else
  1643.     echo "WARNING -- PROBLEMS WERE FOUND..."
  1644. fi
  1645. exit $STATUS
  1646.